#include "scenemanager.h"

#include <fstream>

SceneManager::SceneManager()
	: root("root")
{
}

bool SceneManager::initialize(const std::string & datapath, std::ostream & log)
{
	std::stringstream proxylog;
	if (!joeserialize::LoadObjectFromFile("nodeTypes", datapath+"nodetypes.txt", nodeTypes, false, true, proxylog, proxylog))
	{
		log << proxylog.str();
		return false;
	}
	else
	{
		for (nodeTypes_type::iterator i = nodeTypes.begin(); i != nodeTypes.end(); i++)
		{
			i->second.type = i->first;
		}
		
		assert(nodeTypes.find("folder") != nodeTypes.end());
		root = SceneNode(nodeTypes.find("folder")->second, "root");
		root.allowedChildren.insert("category:render");
		return true;
	}
}

bool SceneManager::load(SceneNode & destination, const std::string & file, std::ostream & log) const
{
	std::stringstream loadlog;
	bool success = joeserialize::LoadObjectFromFile("root", file, destination, false, false, loadlog, loadlog);
	log << loadlog.str();
	
	// if we failed, try again using more lenient settings
	if (!success)
	{
		std::cout << loadlog.str();
		std::cout << "The file loading failed on the first (strict) attempt. Retrying with more lenient settings..." << std::endl;
		success = joeserialize::LoadObjectFromFile("root", file, destination, false, true, log, log);
	}
	
	// upgrade the file if necessary, adding and removing node fields depending on their type
	if (success)
	{
		destination.upgrade(nodeTypes);
		
		// convert paths to absolute locations
		destination.convertPaths(file, false);
	}
	
	return success;
}

bool SceneManager::save(const std::string & file, std::ostream & log)
{
	// copy the node tree and convert the paths
	SceneNode convertedRoot = root;
	convertedRoot.convertPaths(file, true);
	
	return joeserialize::WriteObjectToFile("root", file, convertedRoot, log, false);
}

reseatable_reference <const SceneNode> SceneManager::getNodeType(const std::string & type) const
{
	nodeTypes_type::const_iterator i = nodeTypes.find(type);
	if (i == nodeTypes.end())
		return reseatable_reference <const SceneNode>();
	else
		return reseatable_reference <const SceneNode>(i->second);
}
